﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Navigation;
using CARE.GraphProviderServiceReference;
using prefuse.action.layout;
using GraphLayout.Interface;
using prefuse.action.layout.graph;
using System.Net;


namespace CARE
{
    public partial class SocialNetworks : Page, GraphLayout.Interface.ILayoutControler
    {
        private GraphProviderServiceClient cl = new GraphProviderServiceClient();
        private Layout m_currentlayout;
        private Dictionary<String, Type> typeMap;
        public static Dictionary<GraphElement, GraphLayout.Interface.VisualItem> map = new Dictionary<GraphElement, GraphLayout.Interface.VisualItem>();
        double oldMouseX = 0.0;
        double oldMouseY = 0.0;
        bool mouseLeftButtonPressed = false;
        private bool noZoomValueChanged = false;
        private bool layoutChanged = false;

        public Layout currentlayout
        {
            get
            {
                return m_currentlayout;
            }
            set
            {
                m_currentlayout = value;
                m_currentlayout.Controller = this;
                String name = (from v in typeMap
                               where v.Value == m_currentlayout.GetType()
                               select v.Key).First();
                layoutChooser.SelectedItem = name;
            }
        }

        public SocialNetworks()
        {
            InitializeComponent();            
            this.MouseLeftButtonDown += new MouseButtonEventHandler(rootCanvas_MouseLeftButtonDown);
            this.MouseLeftButtonUp += new MouseButtonEventHandler(rootCanvas_MouseLeftButtonUp);
            this.MouseLeave += new MouseEventHandler(rootCanvas_MouseLeave);
            this.MouseMove += new MouseEventHandler(rootCanvas_MouseMove);
            cl.GetGraphFromGraphMLCompleted += new EventHandler<GetGraphFromGraphMLCompletedEventArgs>(cl_GetGraphFromGraphMLCompleted);
            
        }

        void cl_GetGraphFromGraphMLCompleted(object sender, GetGraphFromGraphMLCompletedEventArgs e)
        {
            Graph m_graph = e.Result;

            rootCanvas.Children.Clear();

            typeMap = Layout.ChildTypesNames(typeof(Layout));
            foreach (var item in typeMap)
                layoutChooser.Items.Add(item.Key);

            SuspendLayout();

            GraphLayout.GraphRepresentation.Graph gg = new GraphLayout.GraphRepresentation.Graph();
            gg.Nodes = new System.Collections.ObjectModel.ObservableCollection<VisualItem>();
            gg.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

            currentlayout = new RadialTreeLayout("", gg, 100);
            currentlayout.setLayoutAnchor(new Point(rootCanvas.ActualWidth / 2.0, rootCanvas.ActualHeight / 2.0));
            currentlayout.Width = this.ActualWidth;
            currentlayout.Height = this.ActualHeight;

            //TODO: check for fiering events twice.            

            map.Clear();

            foreach (var item in m_graph.Vertices)
            {
                var elem = item;
                var node = CreateNodeCanvas(elem, this);
                //node.NodeSelected += new MouseEventHandler(nodeCanvas_NodeSelected);
                gg.Nodes.Add(node);
                ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Graph = gg;
                ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).X = (float)currentlayout.getLayoutAnchor().X;
                ((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).Y = (float)currentlayout.getLayoutAnchor().Y;
                gg.Nodes.Last().Element = item;
                map.Add(item, gg.Nodes.Last());

                //((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseEnter += new MouseEventHandler(SetInfoPanel);
                //((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last()).MouseLeave += new MouseEventHandler(ResetInfoPanel);

                currentlayout.Children.Add((GraphLayout.GraphRepresentation.NodeItem)gg.Nodes.Last());
            }

            //DebugGraph(gg);//test
            foreach (GraphEdge item in m_graph.Edges)
            {
                var n1 = (from v in m_graph.Vertices
                          where v.ID == item.Source
                          select v).First();
                var n2 = (from v in m_graph.Vertices
                          where v.ID == item.Target
                          select v).First();

                GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
                e1.Target = map[n2];
                e1.Source = map[n1];
                e1.Graph = gg;

                gg.Edges.Add(e1);
            }

            try
            {
                currentlayout.Init();
                currentlayout.DrawLayout(100);
            }
            catch (Exception ex)
            {
                rootCanvas.Children.Add(new TextBlock()
                {
                    Text = ex.Message
                });
            };
            currentlayout.SetValue(Grid.ColumnProperty, 1);
            currentlayout.SetValue(Canvas.ZIndexProperty, -10);
            this.rootCanvas.Children.Add(currentlayout);

            ControlPanel.Visibility = Visibility.Visible;
        }

		// Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private void importSocialNetworkButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
			String graphML;
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "XML Files (*.xml)|*.xml|GraphML Files (*.graphml)|*.graphml";
            Nullable<Boolean> result = dialog.ShowDialog();
            if (result.Value == true)
            {
                graphML = dialog.File.OpenText().ReadToEnd();
                cl.GetGraphFromGraphMLAsync(graphML);               
            }
        }

        #region ILayoutControler Members

        public void SuspendLayout()
        {
            foreach (var item in ControlPanel.Children)
            {
                if (item is Button)
                {
                    Button b = item as Button;
                    b.IsEnabled = false;
                }
                else
                    if (item is Slider)
                    {
                        Slider s = item as Slider;
                        s.IsEnabled = false;
                    }
            }

            //m_menu.LeftPanel.Visibility = Visibility.Collapsed;
        }

        public void ResumeLayout()
        {
            foreach (var item in ControlPanel.Children)
            {
                if (item is Button)
                {
                    Button b = item as Button;
                    b.IsEnabled = true;
                }
                else
                    if (item is Slider)
                    {
                        Slider s = item as Slider;
                        s.IsEnabled = true;
                    }
            }
            //m_menu.LeftPanel.Visibility = Visibility.Visible;
        }

        #endregion

        private void rootCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            (sender as SocialNetworks).CaptureMouse();
            mouseLeftButtonPressed = true;
            oldMouseX = e.GetPosition(null).X;
            oldMouseY = e.GetPosition(null).Y;
            (sender as SocialNetworks).Cursor = Cursors.Hand;
        }

        private void rootCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            (sender as SocialNetworks).ReleaseMouseCapture();
            mouseLeftButtonPressed = false;
            (sender as SocialNetworks).Cursor = Cursors.Arrow;
        }

        private void rootCanvas_MouseLeave(object sender, MouseEventArgs e)
        {
            mouseLeftButtonPressed = false;
        }

        private void rootCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (mouseLeftButtonPressed == true && currentlayout.IsMouseCaptured == false)
                foreach (var node in currentlayout.Graph.Nodes)
                {
                    node.X += (float)(e.GetPosition(null).X - oldMouseX);
                    node.Y += (float)(e.GetPosition(null).Y - oldMouseY);
                }
            oldMouseX = e.GetPosition(null).X;
            oldMouseY = e.GetPosition(null).Y;
        }

        private void createSocialNetworkButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            GenerateSocialNetworkWindow win = new GenerateSocialNetworkWindow(true);
            win.Show();
        }

        public static GraphLayout.GraphRepresentation.NodeItem CreateNodeCanvas(GraphElement n, SocialNetworks simulationPage)
        {
            Color projColor = Color.FromArgb(128, 100, 55, 55);

            Brush textColor = new SolidColorBrush(Colors.Black);
            Brush borderColor = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50));

            Brush projBrush = new SolidColorBrush(Colors.LightGray);

            /*TextBlock title = new TextBlock() {
                Foreground = textColor,
                Text = text,
                FontSize = 12
            };*/

            double Height = 25d;
            double Width = 25d;
            //double Width = (title.ActualWidth + 4) < Height ? Height : title.ActualWidth + 4;

            GraphLayout.GraphRepresentation.NodeItem nodeCanvas = new GraphLayout.GraphRepresentation.NodeItem()
            {
                Width = Width,
                Height = Height
            };

            //nodeCanvas.Title = title;

            Ellipse nodeBkg = new Ellipse()
            {
                //Width = Width,
                //Height = Height,
                Width = 25d,
                Height = 25d,
                Fill = projBrush,
                Stroke = borderColor
            };


            //nodeBkg.RadiusX = 10;
            //nodeBkg.RadiusY = 10;

            nodeCanvas.Children.Add(nodeBkg);

            //nodeCanvas.Children.Add(title);

            #region Center the title

            //double left = (nodeBkg.Width - title.ActualWidth) / 2;
            //double top = (nodeBkg.Height - title.ActualHeight) / 2;
            //title.SetValue(Canvas.LeftProperty, left);
            //title.SetValue(Canvas.TopProperty, top);

            #endregion

            return nodeCanvas;
        }

        private void Zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (currentlayout == null || noZoomValueChanged == true)
            {
                noZoomValueChanged = false;
                return;
            }

            double centralX = rootCanvas.ActualWidth / 2;
            double centralY = rootCanvas.ActualHeight / 2;
            //double centralX = currentlayout.Width / 2;
            //double centralY = currentlayout.Height / 2;
            double scale = (e.NewValue + 1) / (e.OldValue + 1);
            foreach (var node in currentlayout.Graph.Nodes)
            {
                double relX = node.X - centralX;
                double relY = node.Y - centralY;

                node.X = (float)(scale * relX + centralX);
                node.Y = (float)(scale * relY + centralY);
            }
        }

        private void LayoutChooser_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            layoutChanged = true;
        }

        private void BalanceGraph_Click(object sender, RoutedEventArgs e)
        {
            Point anchor = currentlayout.getLayoutAnchor();

            noZoomValueChanged = true;
            zoom.Value = 4;

            if (layoutChanged == true)
            {
                layoutChanged = false;

                GraphLayout.GraphRepresentation.Graph g = (GraphLayout.GraphRepresentation.Graph)currentlayout.Graph;
                GraphLayout.GraphRepresentation.Graph graph = new GraphLayout.GraphRepresentation.Graph();
                graph.Nodes = new System.Collections.ObjectModel.ObservableCollection<VisualItem>();
                graph.Edges = new System.Collections.ObjectModel.ObservableCollection<GraphLayout.GraphRepresentation.EdgeItem>();

                GraphLayout.GraphRepresentation.NodeItem root = null;
                if (currentlayout is TreeLayout)
                    root = currentlayout.getLayoutRoot();

                var type = typeMap[layoutChooser.SelectedItem.ToString()];
                //currentlayout.Children.Clear();
                rootCanvas.Children.Remove(currentlayout);
                currentlayout = (Layout)Activator.CreateInstance(type, new object[] { graph });

                Dictionary<VisualItem, VisualItem> mapGGraph = new Dictionary<VisualItem, VisualItem>();
                foreach (var item in g.Nodes)
                {
                    GraphLayout.GraphRepresentation.NodeItem node = (GraphLayout.GraphRepresentation.NodeItem)item;
                    UIElement nodeBkg = node.Children[0];
                    //UIElement title = node.Children[1];
                    node.Children.Clear();
                    GraphLayout.GraphRepresentation.NodeItem nodeCanvas = new GraphLayout.GraphRepresentation.NodeItem()
                    {
                        Width = node.Width,
                        Height = node.Height,
                        //Title = node.Title
                    };
                    //nodeCanvas.NodeSelected += new MouseEventHandler(nodeCanvas_NodeSelected);
                    nodeCanvas.Children.Add(nodeBkg);
                    //nodeCanvas.Children.Add(title);
                    graph.Nodes.Add(nodeCanvas);
                    ((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).Graph = graph;
                    ((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).X = node.X;
                    ((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).Y = node.Y;
                    graph.Nodes.Last().Element = node.Element;
                    mapGGraph.Add(node, graph.Nodes.Last());

                    //((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).MouseEnter += new MouseEventHandler(SetInfoPanel);
                    //((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last()).MouseLeave += new MouseEventHandler(ResetInfoPanel);

                    currentlayout.Children.Add((GraphLayout.GraphRepresentation.NodeItem)graph.Nodes.Last());
                }
                foreach (var edge in g.Edges)
                {
                    var n1 = (from n in g.Nodes
                              where n == edge.Source
                              select n).First();
                    var n2 = (from n in g.Nodes
                              where n == edge.Target
                              select n).First();

                    GraphLayout.GraphRepresentation.EdgeItem e1 = new GraphLayout.GraphRepresentation.EdgeItem();
                    e1.Source = mapGGraph[n1];
                    e1.Target = mapGGraph[n2];
                    e1.Graph = graph;

                    graph.Edges.Add(e1);
                }

                Dictionary<GraphElement, VisualItem> newMap = new Dictionary<GraphElement, VisualItem>();
                GraphLayout.Interface.VisualItem vi = null;
                foreach (var item in map)
                    if (mapGGraph.TryGetValue(item.Value, out vi) == true)
                        newMap.Add(item.Key, mapGGraph[item.Value]);
                map = newMap;

                if (root != null && currentlayout is TreeLayout)
                    ((TreeLayout)currentlayout).setLayoutRoot((GraphLayout.GraphRepresentation.NodeItem)mapGGraph[root]);

                if (g.PreviousSelectedNode != null)
                    graph.PreviousSelectedNode = mapGGraph[g.PreviousSelectedNode];
                if (g.SelectedNode != null)
                {
                    graph.SelectedNode = mapGGraph[g.SelectedNode];
                    SelectNode((GraphLayout.GraphRepresentation.NodeItem)mapGGraph[g.SelectedNode]);
                }

                //currentlayout.Width = m_menu.ContentHost.Width;
                //currentlayout.Height = m_menu.ContentHost.Height;
                currentlayout.Width = this.Width;
                currentlayout.Height = this.Height;
                currentlayout.SetValue(Canvas.TopProperty, 1.0);
                currentlayout.SetValue(Canvas.LeftProperty, 1.0);
                rootCanvas.Children.Insert(0, currentlayout);
            }

            currentlayout.setLayoutAnchor(anchor);

            currentlayout.Init();
            currentlayout.DrawLayout(100);
        }

        private void SelectNode(GraphLayout.GraphRepresentation.NodeItem node)
        {
            node.Select();
        }
	}
}
